package dataStructures.cachedIndex;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import org.apache.xerces.parsers.SAXParser;

import xml.IdToRouteCachedIndexHandler;
import xml.XmlStatisticsHandler;

public class IdToRouteCachedIndex 
{
	private RandomAccessFile _raf = null;
	
	private LinkedHashMap<String,Integer> _labelsToIdMap = null;
	private LinkedHashMap<ArrayList<Integer>,Integer> _routeToIdMap = null;
	
	private ArrayList<String> _labelsList = new ArrayList<String>();
	private ArrayList<ArrayList<Integer>> _routesList = new ArrayList<ArrayList<Integer>>();
	
	
	private long _nodesBase = 0;
	
	private byte[] _cache;
	private int _cacheIndex = 0;
	
	public IdToRouteCachedIndex(String indexFile) throws Exception
	{
		_raf = new RandomAccessFile(indexFile,"rws");
		_labelsToIdMap = new LinkedHashMap<String, Integer>();
		_routeToIdMap = new LinkedHashMap<ArrayList<Integer>, Integer>();
		
		_nodesBase = _raf.readLong();
		int numberOfLabels = _raf.readInt();

		//deserialize labels
		for(int i = 0 ; i < numberOfLabels ; ++i)
		{
			String l = _raf.readUTF();
			_labelsList.add(l);
			_labelsToIdMap.put(l,_labelsToIdMap.size());
		}

		int numberOfRouts = _raf.readInt();
		
		for(int i = 0 ; i < numberOfRouts ; ++i)
		{
			int routeLength = _raf.readInt();
			ArrayList<Integer> route = new ArrayList<Integer>(routeLength);
			
			for(int j = 0 ; j < routeLength ; ++j)
			{
				route.add(_raf.readInt());
			}
			
			_routesList.add(route);
			_routeToIdMap.put(route,_routeToIdMap.size());
		}
		//read routes
	}
	
	private void WriteIndexMetaData() throws Exception
	{
		//make room for the address of the nodes
		_raf.writeLong(0);
		
		//number of labels
		_raf.writeInt(_labelsToIdMap.size());
		
		//serialize labels
		for(String l : _labelsToIdMap.keySet())
		{
			_raf.writeUTF(l);
			_labelsList.add(l);
		}
		
		//number of routs
		_raf.writeInt(_routeToIdMap.size());
		
		//serialize routes
		for(ArrayList<Integer> route : _routeToIdMap.keySet())
		{
			_routesList.add(route);
			_raf.writeInt(route.size());
			for(int lid : route)
			{
				_raf.writeInt(lid);
			}

		}

		_nodesBase = _raf.getFilePointer();
		
		_raf.seek(0);
		_raf.writeLong(_nodesBase);
		_raf.seek(_nodesBase);
	}
	public IdToRouteCachedIndex(String indexFile,String xmlFile) throws Exception
	{
		//delete old index file since we are creating new one
		new File(indexFile).delete();
		_raf = new RandomAccessFile(indexFile,"rws");

		SAXParser saxParser = new SAXParser();
		XmlStatisticsHandler statsHandler = new XmlStatisticsHandler();
		saxParser.setContentHandler(statsHandler);
		saxParser.parse(xmlFile);
		
		_labelsToIdMap =  statsHandler.GetLabels();
		_routeToIdMap = statsHandler.GetRouts();

		WriteIndexMetaData();
		
		_cache = new byte[1000000];
		
		saxParser.setContentHandler(new IdToRouteCachedIndexHandler(this));
		saxParser.parse(xmlFile);
		
		//flush cache
		FlushCache();
		//release cache
		_cache = null;
		System.gc();

		//_cache.clear();
		
		
		
	}
	
	private void FlushCache() throws Exception
	{
		_raf.write(_cache, 0, _cacheIndex);
		_cacheIndex = 0;
		/*ByteBuffer byteBuffer = ByteBuffer.allocate(_cache.length * 4);        
        IntBuffer intBuffer = byteBuffer.asIntBuffer();
        intBuffer.put(_cache);
        
        byte[] array = byteBuffer.array();
        
        _raf.write(byteBuffer.array(),0,_cacheIndex);
        
        _cacheIndex = 0;
        */
		
		/*ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream dos = new DataOutputStream(baos);
		for(int i : _cache)
		{
			dos.writeInt(i);
		}

		_raf.write(baos.toByteArray());
		
		dos.close();
		*/

        
	}
	public int GetlabelId(String label)
	{
		return _labelsToIdMap.get(label);
	}
	
	public int GetRouteId(ArrayList<Integer> route)
	{
		return _routeToIdMap.get(route);
	}
	
	 
	public void SetNodesRoute(int nodeId,ArrayList<Integer> route) throws Exception
	{
		//_raf.seek(_nodesBase + nodeId*4);
		//_raf.writeInt(_routeToIdMap.get(route));
		if (_cacheIndex == 1000000)
		{
			FlushCache();
		}
		
		int routeId = _routeToIdMap.get(route);
		_cache[_cacheIndex++] = (byte)(routeId >>> 24);
		_cache[_cacheIndex++] = (byte)(routeId >>> 16);
		_cache[_cacheIndex++] = (byte)(routeId >>> 8);
		_cache[_cacheIndex++] = (byte)routeId;
		
		//_cache.add(_routeToIdMap.get(route));

	}
	
	public ArrayList<Integer> GetNodeRoute(int nodeId) throws Exception
	{
		_raf.seek(_nodesBase + nodeId*4);
		int routeId = _raf.readInt();
		return _routesList.get(routeId);
	}
	
	public void Close() throws Exception
	{
		_raf.close();
	}
	
	
	public static void main(String[] args) throws Exception
	{
		RandomAccessFile raf = new RandomAccessFile("d:\\data123.dat","rw");
		raf.seek(2047);
		raf.writeByte(1);
		raf.close();
		
		//new IdToRouteCachedIndex("D:\\development\\dblab\\workingDirectory\\idtoroute.idx","D:\\development\\dblab\\xmlDocs\\dblp.xml");
		//new IdToRouteCachedIndex("D:\\development\\dblab\\workingDirectory\\idtoroute.idx");
	}
	
	
}
